package com.lhb.ojjudgeservice.judge;

import cn.hutool.json.JSONUtil;
import com.lhb.ojcommon.common.ErrorCode;
import com.lhb.ojcommon.exception.BusinessException;
import com.lhb.ojjudgeservice.judge.codesanbox.CodeSanBox;
import com.lhb.ojjudgeservice.judge.codesanbox.CodeSanBoxFactory;
import com.lhb.ojjudgeservice.judge.judgestrategy.StrategyContext;
import com.lhb.ojmodel.model.codesandbox.ExecuteCodeRequest;
import com.lhb.ojmodel.model.codesandbox.ExecuteCodeResponse;
import com.lhb.ojmodel.model.dto.question.JudgeCase;
import com.lhb.ojmodel.model.dto.questionsubmit.JudgeInfo;
import com.lhb.ojmodel.model.entity.Question;
import com.lhb.ojmodel.model.entity.QuestionSubmit;
import com.lhb.ojmodel.model.enums.QuestionSubmitStatusEnum;
import com.lhb.ojserviceclient.feignclient.QuestionFeignClient;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;


@Service
public class JudgeServiceImpl implements JudgeService {
    @Resource
    private QuestionFeignClient questionFeignClient;

    @Resource
    private JudgeManager judgeManager;

    @Value("${codeSanBox.type}")
    private String type;

    @Override
    public QuestionSubmit doJudge(long questionSubmitId) {
        //根据id获取题目信息、提交题目信息
        QuestionSubmit questionSubmit = questionFeignClient.getQuestionSubmitById(questionSubmitId);
        if (questionSubmit == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交记录不存在");
        }
        long questionId = questionSubmit.getQuestionId();
        Question question = questionFeignClient.getById(questionId);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }

        //如果题目提交状态不为等待中，就不用重复执行
        if (!questionSubmit.getStatus().equals(QuestionSubmitStatusEnum.WAIT.getValue())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目状态不是等待中，无法执行");
        }

        //更改判题的状态为"判题中",防止重复执行，也能让用户即时看到状态
        QuestionSubmit questionSubmit1 = new QuestionSubmit();
        questionSubmit1.setStatus(QuestionSubmitStatusEnum.JUDGE.getValue());
        questionSubmit1.setId(questionSubmitId);
        questionFeignClient.updateById(questionSubmit1);

        //调用沙箱，获取到执行结果
        CodeSanBox codeSanBox = CodeSanBoxFactory.create(type);
        //获取输入输出用例
        String judgeCaseStr = question.getJudgeCase();
        List<String> inputList = JSONUtil.toList(judgeCaseStr, JudgeCase.class).stream().map(JudgeCase::getInput).collect(Collectors.toList());
        List<String> outputList = JSONUtil.toList(judgeCaseStr, JudgeCase.class).stream().map(JudgeCase::getOutput).collect(Collectors.toList());
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(questionSubmit.getCode()).input(inputList).language(questionSubmit.getLanguage()).build();
        ExecuteCodeResponse executeCodeResponse = codeSanBox.executeCode(executeCodeRequest);
        if (executeCodeResponse.getJudgeInfo() == null || executeCodeResponse.getOutput() == null) {
            QuestionSubmit questionSubmit2 = new QuestionSubmit();
            JudgeInfo judgeInfo = new JudgeInfo();
            judgeInfo.setMessage("运行错误");
            questionSubmit2.setStatus(3);//直接设置状态为失败
            questionSubmit2.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
            questionSubmit2.setId(questionSubmitId);
            boolean b = questionFeignClient.updateById(questionSubmit2);
            if (!b) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "更新错误");
            }
            return null;
        }
        StrategyContext strategyContext = StrategyContext.builder()
                .judgeInfo(executeCodeResponse.getJudgeInfo()).question(question).outputList(outputList)
                .judgeOutputList(executeCodeResponse.getOutput()).questionSubmit(questionSubmit).build();

        JudgeInfo judgeInfo = judgeManager.judge(strategyContext);

        questionSubmit1 = new QuestionSubmit();
        questionSubmit1.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
        questionSubmit1.setId(questionSubmitId);
        questionSubmit1.setStatus(QuestionSubmitStatusEnum.SUCCESS.getValue());
        boolean update = questionFeignClient.updateById(questionSubmit1);
        if (!update) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "更新错误");
        }

        return questionFeignClient.getQuestionSubmitById(questionSubmitId);
    }
}
